package cn.fanyamin.util.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;


public class ReflectUtils {
	public static Object createBean(String className, String factoryMethod) throws Exception {
		Class<?> cls = Class.forName(className);
		if(null == factoryMethod) {
			return cls.newInstance();
		}
		Method method = cls.getMethod(factoryMethod, new Class[0]);
		return method.invoke(cls, new Object[0]);		
	}
	
	public static Object createObjectByName(String className) throws Exception {				
		return createBean(className, null);
	}
	
	public static Method createMethodByName(Object sqlObj, String methodName, Object[] parameters)  {
		Class[] types = null;
		if (null != parameters && parameters.length > 0) {
			types = new Class[parameters.length];
			for (int i = 0; i < parameters.length; i++) {
				types[i] = parameters[i].getClass();
			}
		}

		try {
			return sqlObj.getClass().getDeclaredMethod(methodName, types);
		} catch (SecurityException e) {
			throw new RuntimeException(e);
		} catch (NoSuchMethodException e) {
			throw new RuntimeException(e);
		}
	}
	
	public static String genMethodsByPrefix(Class clazz, String prefix) {
		Method[] methods = clazz.getDeclaredMethods();
		
		StringBuilder sb = new StringBuilder();
		String objName = getObjectName(clazz);
		sb.append(clazz.getSimpleName() + " " + objName + " = ");
		sb.append("new " + clazz.getSimpleName() + "();\n");
		for (Method mh : methods) {
			if(mh.getName().startsWith(prefix)) {
				sb.append(objName + ".");
				sb.append(mh.getName() + "();\n");
			}
		}
		return sb.toString();
	}
	//TODO: use sink for reduce repeat
	public static String genSetMethodsWithJson(Class clazz) {
		
		StringBuilder sb = new StringBuilder();
		String objName = getObjectName(clazz);
		sb.append(clazz.getSimpleName() + " " + objName + " = ");
		sb.append("new " + clazz.getSimpleName() + "();\n");
		
		appendSetMethods(clazz, objName, sb);
		
		return sb.toString();
	}

	private static String getObjectName(Class clazz) {
		String objName = clazz.getSimpleName().substring(0, 1).toLowerCase()
				+ clazz.getSimpleName().substring(1);
		return objName;
	}

	private static void appendSetMethods(Class clazz, String objName, StringBuilder sb) {
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			sb.append(objName  + ".set"
					+ field.getName().substring(0, 1).toUpperCase());
			sb.append(field.getName().substring(1) + "(");
			sb.append("jsonObj.get");
			sb.append(field.getType().getName().substring(0, 1).toUpperCase());
			sb.append(field.getType().getName().substring(1));
			sb.append("(\"");
			sb.append(field.getName() + "\"));\n");						
		}
		if(clazz.getSuperclass()!= Object.class) {
			sb.append("//" + clazz.getSuperclass().getSimpleName() +"\n");				
			appendSetMethods(clazz.getSuperclass(), objName, sb);
		}
	}
	
	public static String genSetMethods(Class clazz) {
		Collection<Field> fields = getFields(clazz);
		StringBuilder sb = new StringBuilder();
		String objName = getObjectName(clazz);
		sb.append(clazz.getSimpleName() + " " + objName + " = ");
		sb.append("new " + clazz.getSimpleName() + "();\n");
		for (Field field : fields) {
			sb.append(objName + ".set"
					+ field.getName().substring(0, 1).toUpperCase());
			sb.append(field.getName().substring(1) + "(");
			sb.append(field.getName() + ");");
			sb.append(" //" + field.getType().getName() + "\n");
		}
		return sb.toString();
	}
	
	
	public static String genGetMethods(Class clazz) {		
		return genMethodsByPrefix(clazz, "get");
	}
	
	public static Collection<Field> getFields(Class clazz) {		
		List<Field> aList = new LinkedList<Field>();
		appendField(clazz, aList);
		while(clazz.getSuperclass()!= Object.class) {
			clazz = clazz.getSuperclass();
			appendField(clazz, aList);
		}
		return aList;
	}
	
	private static void appendField(Class clazz, Collection<Field> aList) {
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			aList.add(field);
		}
	}
	
	public static String genToStringMethod(Class clazz) {
		Field[] fields = clazz.getDeclaredFields();
		StringBuilder sb = new StringBuilder();
		sb.append("public String toString() {\n");
		sb.append("\tStringBuilder sb = new StringBuilder();\n");
		sb.append("\tsb.append(\"" + clazz.getSimpleName() + "\");\n");
		for (Field field : fields) {
			sb.append("\tsb.append(\", " + field.getName() + "=\");\n");
			sb.append("\tsb.append(" + field.getName() + ");\n");
		}
		sb.append("\treturn sb.toString();\n");
		sb.append("}\n");
		return sb.toString();
	}
	
	public static void main(String[] args) {
		System.out.println(genSetMethodsWithJson(java.io.FileInputStream.class));
	}
}
